#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<pthread.h>
#include<unistd.h>


/*
   利用条件变量实现两个线程的生产者和消费者
 */

//创建一个结构体，表示链表节点
typedef struct  Node
{
	int data;
	struct Node* pNext;
}NODE;

//定义互斥锁
pthread_mutex_t mutex;
//定义条件变量
pthread_cond_t cond;

//创建一个头节点
NODE * pHead = NULL;


void *product_thread(void *val)
{
	char a = *(char*)val;
	NODE* pNode = NULL;
	while(1)
	{
		//生产者创建节点
		pNode = (NODE*)malloc(sizeof(NODE));
		//给节点赋值
		pNode->data = rand()%1000;
		pNode->pNext = NULL;
		printf("[%c]---->[%d]\n",a,pNode->data);
		//加锁
		pthread_mutex_lock(&mutex);

		//利用头插，将节点插入链表中
		pNode->pNext = pHead;
		pHead = pNode;

		//解锁
		pthread_mutex_unlock(&mutex);

		//通知消费者线程解除阻塞
		pthread_cond_signal(&cond);

		usleep(500);
	}
}

void *consumer_thread(void *val)
{
	char b = *(char*)val;
	//消费者删除节点
	NODE *pNode =NULL;
	while(1)
	{
		//加锁
		pthread_mutex_lock(&mutex);

		//判断链表是否为空
		if(pHead == NULL)
		{
			//若条件不满足,需要阻塞等待
			//若条件不满足,则阻塞等待并解锁;
			//若条件满足(被生成者线程调用pthread_cond_signal函数通知),解除阻塞并加锁 
			pthread_cond_wait(&cond, &mutex);	
		}
		pNode = pHead;
		//打印输出当前节点，并free
		printf("[%c]---->[%d]\n",b,pNode->data);
		pHead = pNode->pNext;

		//解锁
		pthread_mutex_unlock(&mutex);


		free(pNode);
		pNode = NULL;

		usleep(500);
	}
}

int main()
{
	//初始化互斥锁
	pthread_mutex_init(&mutex,NULL);
	//初始化条件变量
	pthread_cond_init(&cond,NULL);
	//创建两个线程
	pthread_t thread[2];
	char a = 'P';
	int ret = pthread_create(&thread[0],NULL,product_thread,&a); //生产者
	if(ret != 0)                          
	{                                    
		printf("thread creat error,[%s]\n",strerror(ret));
		return -1;                         
	}                        

	char b = 'C';
	ret = pthread_create(&thread[1],NULL,consumer_thread,&b);//消费者
	if(ret != 0)                          
	{                                    
		printf("thread creat error,[%s]\n",strerror(ret));
		return -1;                         
	}                        

	//回收线程
	pthread_join(thread[0],NULL);
	pthread_join(thread[1],NULL);	

	//摧毁锁和条件变量
	pthread_mutex_destroy(&mutex);
	pthread_cond_destroy(&cond);

	return 0;
}
